/**
 * @file eeprom.c
 * @author Morris (morris@mnblog.cn)
 * @brief
 * @version 0.0.1
 * @date 2022-02-22
 *
 * @copyright Copyright (c) 2022
 *
 */
#include "eeprom.h"

#include "acommon_err.h"
#include "bsp.h"
#include "gpio.h"
#include "i2c.h"

#define EEPROM_DERVICE_ADDRESS 0xA0
#define EEPROM_PAGE_SIZE       (32U)

#define eeprom_delay(x)        relay_delay_ms(x)

static void _i2c_gpio_init(void);
static void _i2c_init(void);

static acommon_err_t i2c_read_16bit(uint8_t slave_address, uint16_t mem_address,
                                    uint8_t* data, uint16_t data_size);
static acommon_err_t i2c_write_16bit(uint8_t  slave_address,
                                     uint16_t mem_address, uint8_t* data,
                                     uint16_t data_size);

static void relay_delay_ms(uint32_t tick)
{
    volatile uint32_t _tick = tick * 0x1FF;
    while (_tick--)
        ;
}

/**
 * @brief i2c端口初始化
 *
 */
static void _i2c_gpio_init(void)
{
    stc_gpio_cfg_t stcGpioCfg;

    DDL_ZERO_STRUCT(stcGpioCfg);

    Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio, TRUE);

    stcGpioCfg.enDir = GpioDirOut;
    stcGpioCfg.enOD  = GpioOdEnable;  ///< i2c 开漏输出
    stcGpioCfg.enPu  = GpioPuDisable; ///< 无需上下拉，外部上拉
    stcGpioCfg.enPd  = GpioPdDisable;

    Gpio_Init(EEPROM_I2C_SCL_PORT, EEPROM_I2C_SCL_PIN, &stcGpioCfg);
    Gpio_Init(EEPROM_I2C_SDA_PORT, EEPROM_I2C_SDA_PIN, &stcGpioCfg);
    Gpio_SetIO(EEPROM_I2C_SCL_PORT, EEPROM_I2C_SCL_PIN);
    Gpio_SetIO(EEPROM_I2C_SDA_PORT, EEPROM_I2C_SDA_PIN);

    Gpio_SetAfMode(EEPROM_I2C_SCL_PORT, EEPROM_I2C_SCL_PIN,
                   EEPROM_I2C_SCL_GPIO_AF);
    Gpio_SetAfMode(EEPROM_I2C_SDA_PORT, EEPROM_I2C_SDA_PIN,
                   EEPROM_I2C_SDA_GPIO_AF);
}

/**
 * @brief 初始化i2c
 *
 */
static void _i2c_init(void)
{
    stc_i2c_cfg_t stcI2cCfg;

    DDL_ZERO_STRUCT(stcI2cCfg);

    Sysctrl_SetPeripheralGate(EEPROM_I2C_PERICLK, TRUE);
    I2C_ClearFunc(EEPROM_I2C_PORT, I2cModule_En);

    stcI2cCfg.u32Pclk = Sysctrl_GetPClkFreq();
    stcI2cCfg.u32Baud = 30000; ///< 波特率30kHz
    stcI2cCfg.enMode  = I2cMasterMode;
    I2C_Init(EEPROM_I2C_PORT, &stcI2cCfg);
}

en_result_t I2C_WaitIrq(const M0P_I2C_TypeDef* pstcI2Cx, uint32_t u32Timeout)
{
    en_result_t enRet = ErrorTimeout;

    for (;;)
    {
        if (0 != I2C_GetIrq(EEPROM_I2C_PORT)) enRet = Ok;

        if ((Ok == enRet) || (0UL == u32Timeout)) { break; }
        else { u32Timeout--; }
    }

    return enRet;
}

/**
 * @brief i2c 从16bit寄存器读出buff数据
 *
 * @param slave_address  从机地址(8bit)
 * @param mem_address     寄存器(内存)地址
 * @param data
 * @param data_size
 * @return en_result_t
 */
static acommon_err_t i2c_read_16bit(uint8_t slave_address, uint16_t mem_address,
                                    uint8_t* data, uint16_t data_size)
{
    uint8_t _state;

    I2C_SetFunc(EEPROM_I2C_PORT, I2cStart_En);

    // start and slave address
    if (I2C_WaitIrq(EEPROM_I2C_PORT, 0x000fffff) != Ok) goto _END;
    _state = I2C_GetState(EEPROM_I2C_PORT);
    if (_state == 0x08 || _state == 0x10)
    {
        I2C_WriteByte(EEPROM_I2C_PORT, slave_address); ///< 从设备地址发送
        I2C_ClearFunc(EEPROM_I2C_PORT, I2cStart_En);
        I2C_ClearIrq(EEPROM_I2C_PORT); ///< 清除中断状态标志位
    }
    else { goto _END; }

    // send Word Address
    if (I2C_WaitIrq(EEPROM_I2C_PORT, 0x000fffff) != Ok) goto _END;
    _state = I2C_GetState(EEPROM_I2C_PORT);

    if (_state == 0x18)
    {
        I2C_WriteByte(EEPROM_I2C_PORT,
                      (mem_address >> 8) & 0xff); ///< 从设备内存地址发送
        I2C_ClearIrq(EEPROM_I2C_PORT); ///< 清除中断状态标志位
    }
    else { goto _END; }

    if (I2C_WaitIrq(EEPROM_I2C_PORT, 0x000fffff) != Ok) goto _END;
    _state = I2C_GetState(EEPROM_I2C_PORT);

    if (_state == 0x28)
    {
        I2C_WriteByte(EEPROM_I2C_PORT,
                      mem_address & 0xff); ///< 从设备内存地址发送
        I2C_ClearIrq(EEPROM_I2C_PORT);     ///< 清除中断状态标志位
    }
    else { goto _END; }

    if (I2C_WaitIrq(EEPROM_I2C_PORT, 0x000fffff) != Ok) goto _END;
    _state = I2C_GetState(EEPROM_I2C_PORT);
    if (_state == 0x28)
    {
        I2C_SetFunc(EEPROM_I2C_PORT, I2cStart_En); ///< 发送重复起始条件
        I2C_ClearIrq(EEPROM_I2C_PORT); ///< 清除中断状态标志位
    }
    else { goto _END; }

    if (I2C_WaitIrq(EEPROM_I2C_PORT, 0x000fffff) != Ok) goto _END;
    _state = I2C_GetState(EEPROM_I2C_PORT);
    if (_state == 0x08 || _state == 0x10)
    {
        I2C_WriteByte(EEPROM_I2C_PORT,
                      slave_address | 0x01); ///< 从设备地址发送
        I2C_ClearFunc(EEPROM_I2C_PORT, I2cStart_En);
        I2C_ClearIrq(EEPROM_I2C_PORT);       ///< 清除中断状态标志位
    }
    else { goto _END; }

    if (I2C_WaitIrq(EEPROM_I2C_PORT, 0x000fffff) != Ok) goto _END;
    _state = I2C_GetState(EEPROM_I2C_PORT);
    if (_state == 0x40)
    {
        if (data_size > 1)
            I2C_SetFunc(EEPROM_I2C_PORT, I2cAck_En); ///< 使能主机应答功能
        I2C_ClearIrq(EEPROM_I2C_PORT); ///< 清除中断状态标志位
    }
    else { goto _END; }

    for (int i = 0; i < data_size; i++)
    {
        if (I2C_WaitIrq(EEPROM_I2C_PORT, 0x000fffff) != Ok) goto _END;
        _state = I2C_GetState(EEPROM_I2C_PORT);
        if (_state == 0x50 || _state == 0x58)
        {
            if (i == data_size - 2)
            {
                I2C_ClearFunc(
                    EEPROM_I2C_PORT,
                    I2cAck_En); ///< 已接收到倒数第二个字节，关闭ACK应答功能
            }
            else if (_state == 0x58)
            {
                I2C_SetFunc(EEPROM_I2C_PORT, I2cStop_En); ///< 发送停止条件
            }
            data[i] = I2C_ReadByte(EEPROM_I2C_PORT);

            I2C_ClearIrq(EEPROM_I2C_PORT); ///< 清除中断状态标志位
        }
        else { goto _END; }
    }

    return ACOMMON_OK;

_END:
    I2C_SetFunc(EEPROM_I2C_PORT, I2cStop_En);
    I2C_ClearIrq(EEPROM_I2C_PORT); ///< 清除中断状态标志位

    return ACOMMON_FAIL;
}

/**
 * @brief
 *
 * @param slave_address
 * @param mem_address
 * @param data
 * @param data_size
 * @return en_result_t
 */
static acommon_err_t i2c_write_16bit(uint8_t  slave_address,
                                     uint16_t mem_address, uint8_t* data,
                                     uint16_t data_size)
{
    acommon_err_t res = ACOMMON_FAIL;
    uint8_t       _state;
    I2C_SetFunc(EEPROM_I2C_PORT, I2cStart_En);

    // start and slave address
    if (I2C_WaitIrq(EEPROM_I2C_PORT, 0x000fffff) != Ok) goto _END;
    _state = I2C_GetState(EEPROM_I2C_PORT);
    if (_state == 0x08 || _state == 0x10)
    {
        I2C_WriteByte(EEPROM_I2C_PORT, slave_address); ///< 从设备地址发送
        I2C_ClearFunc(EEPROM_I2C_PORT, I2cStart_En);
        I2C_ClearIrq(EEPROM_I2C_PORT); ///< 清除中断状态标志位
    }
    else
    {
        res -= 1;
        goto _END;
    }

    // send Word Address
    if (I2C_WaitIrq(EEPROM_I2C_PORT, 0x000fffff) != Ok) goto _END;
    _state = I2C_GetState(EEPROM_I2C_PORT);

    if (_state == 0x18)
    {
        I2C_WriteByte(EEPROM_I2C_PORT,
                      (mem_address >> 8) & 0xff); ///< 从设备内存地址发送
        I2C_ClearIrq(EEPROM_I2C_PORT); ///< 清除中断状态标志位
    }
    else
    {
        res -= 2;
        goto _END;
    }

    if (I2C_WaitIrq(EEPROM_I2C_PORT, 0x000fffff) != Ok) goto _END;
    _state = I2C_GetState(EEPROM_I2C_PORT);

    if (_state == 0x28)
    {
        I2C_WriteByte(EEPROM_I2C_PORT,
                      mem_address & 0xff); ///< 从设备内存地址发送
        I2C_ClearIrq(EEPROM_I2C_PORT);     ///< 清除中断状态标志位
    }
    else
    {
        res -= 3;
        goto _END;
    }

    // send data
    for (int i = 0; i < data_size; i++)
    {
        if (I2C_WaitIrq(EEPROM_I2C_PORT, 0x000fffff) != Ok) goto _END;
        _state = I2C_GetState(EEPROM_I2C_PORT);
        if (_state == 0x28)
        {
            I2C_WriteByte(EEPROM_I2C_PORT, data[i]); ///< 从设备内存地址发送
            I2C_ClearIrq(EEPROM_I2C_PORT); ///< 清除中断状态标志位
        }
        else { break; }
    }

    res = ACOMMON_OK;

_END:
    if (I2C_WaitIrq(EEPROM_I2C_PORT, 0x000fffff) != Ok) goto _END;
    _state = I2C_GetState(EEPROM_I2C_PORT);
    I2C_SetFunc(EEPROM_I2C_PORT, I2cStop_En);
    I2C_ClearIrq(EEPROM_I2C_PORT); ///< 清除中断状态标志位
    return res;
}

/**
 * @brief eepromc初始化
 *
 * @return int32_t
 */
void eeprom_init(void)
{
    _i2c_gpio_init();

    _i2c_init();

    // I2C_SetFunc(EEPROM_I2C_PORT, I2cStart_En);
}

acommon_err_t eeprom_write_buff(uint16_t reg, uint8_t* data, uint16_t len)
{
    acommon_err_t res   = ACOMMON_OK;
    uint16_t      size  = 0;
    uint16_t      index = 0;
    //   uint16_t page   = reg >> 6;   //当前地址所在的页
    uint16_t offset = reg & (EEPROM_PAGE_SIZE - 1); //当前地址所在也的偏移量

    size = ((offset + len) > EEPROM_PAGE_SIZE) ? (EEPROM_PAGE_SIZE - offset)
                                               : len;

    while (index < len && res == ACOMMON_OK)
    {
        eeprom_delay(10);

        res = i2c_write_16bit(EEPROM_DERVICE_ADDRESS, reg + index, data + index,
                              size);
        ACOMMON_LOGV("%s[%d] address[%04x(%d)] data[%d] size %d", __func__, res,
                     reg + index, reg + index, index, size);

        index += size;
        size   = ((len - index) > EEPROM_PAGE_SIZE) ? EEPROM_PAGE_SIZE
                                                    : (len - index);
    }

    return res;
}

acommon_err_t eeprom_read_buff(uint16_t reg, uint8_t* data, uint16_t len)
{
    return i2c_read_16bit(EEPROM_DERVICE_ADDRESS, reg, data, len);
}

void eeprom_test(void)
{
    uint8_t data[168] = {0}, data2[256] = {0};

    eeprom_init();

    for (int j = 0; j < sizeof(data); j++) { data[j] = j; }

    ///< eeprom写数据
    // acommon_log_buffer_hex("write", data, sizeof(data), ACOMMON_LOG_INFO);
    eeprom_write_buff(3, data, sizeof(data));
    eeprom_delay(100);

    ///< eeprom读数据
    eeprom_read_buff(0, data2, sizeof(data2));
    // acommon_log_buffer_hex("read", data2, sizeof(data2), ACOMMON_LOG_INFO);
}
